package com.example.demo.service.impl;

import com.example.demo.dto.*;
import com.example.demo.entity.Goods;
import com.example.demo.entity.Orders;
import com.example.demo.entity.OrdersItem;
import com.example.demo.enums.OrdersStatusEnum;
import com.example.demo.repository.GoodsRepository;
import com.example.demo.repository.OrdersItemRepository;
import com.example.demo.repository.OrdersRepository;
import com.example.demo.service.OrdersService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.Predicate;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * OrdersServiceImpl
 *  订单service
 * @author liujin
 * @date 2020/12/18 14:01
 */
@Slf4j
@Service
public class OrdersServiceImpl implements OrdersService {

    @Autowired
    private OrdersRepository ordersRepository;

    @Autowired
    private GoodsRepository goodsRepository;

    @Autowired
    private OrdersItemRepository ordersItemRepository;

    /**
     * 功能描述: 下单
     * @param: [request]
     * @author: liujin
     * @date: 2020/12/18 14:17
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void placeOrder(PlaceOrderRequest request) {
        final Long customerId = request.getCustomerId();
        log.info("用户 {} 开始下单", customerId);

        // 填充订单基本信息
        Orders orders = newOrders(request);

        // 扣除库存
        reduceStock(orders);

        //计算订单金额
        calculationAmount(orders);

        // 保存订单
        Orders dbOrders = ordersRepository.saveAndFlush(orders);

        //保存orderItem
        List<OrdersItem> itemList = orders.getItemList();
        itemList.forEach(item -> item.setOrderId(dbOrders.getId()));
        ordersItemRepository.saveAll(itemList);
    }

    /**
     * 功能描述: 计算订单金额
     * @param: [orders]
     * @author: liujin
     * @date: 2020/12/18 15:19
     */
    private void calculationAmount(Orders orders) {
        BigDecimal amount = BigDecimal.ZERO;
        for (OrdersItem ordersItem : orders.getItemList()) {
            Long goodsId = ordersItem.getGoodsId();
            Goods goods = goodsRepository.findById(goodsId).orElseThrow(() -> new RuntimeException("商品不存在"));
            BigDecimal price = goods.getPrice().multiply(new BigDecimal(ordersItem.getQuantity().toString())).setScale(2, BigDecimal.ROUND_HALF_UP);
            amount = amount.add(price);
        }
        orders.setAmount(amount);
    }

    /**
     * 功能描述: 扣除库存
     * @param: [orders]
     * @author: liujin
     * @date: 2020/12/18 15:19
     */
    private void reduceStock(Orders orders) {
        for (OrdersItem ordersItem : orders.getItemList()) {
            Long goodsId = ordersItem.getGoodsId();
            Integer quantity = ordersItem.getQuantity();
            Assert.isTrue(quantity > 0, "扣除数量必须大于0");
            int affectedRows = goodsRepository.reduceStock(goodsId, quantity);
            Assert.isTrue(affectedRows > 0, "商品库存不足");
        }
    }

    /**
     * 功能描述: 填充订单基本信息
     * @param: [customerId]
     * @author: liujin
     * @date: 2020/12/18 14:42
     */
    private Orders newOrders(PlaceOrderRequest request) {
        Orders orders = new Orders();
        orders.setCustomerId(request.getCustomerId());
        orders.setCreateDate(LocalDateTime.now());
        orders.setSn(generateSn());
        orders.setStatus(OrdersStatusEnum.INIT);
        orders.setAmount(BigDecimal.ZERO);

        List<OrdersItem> ordersItems = new ArrayList<>();
        for (OrderItemRequest orderItemRequest : request.getOrderItemSet()) {
            OrdersItem ordersItem = new OrdersItem();
            ordersItem.setGoodsId(orderItemRequest.getGoodsId());
            ordersItem.setQuantity(orderItemRequest.getQuantity());
            ordersItem.setCompleteNum(0);
            ordersItems.add(ordersItem);
        }
        orders.setItemList(ordersItems);
        return orders;
    }

    /**
     * 功能描述: 生成订单编号
     * @param: []
     * @author: liujin
     * @date: 2020/12/18 14:26
     */
    private String generateSn() {
        return UUID.randomUUID().toString();
    }


    /**
     * 功能描述: 修改订单（加菜、退菜)
     * @param: [request]
     * @author: liujin
     * @date: 2020/12/18 15:58
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void modifyOrder(ModifyOrderRquest request) {
        final String orderSn = request.getOrderSn();
        Orders orders = ordersRepository.findOrdersBySn(orderSn).orElseThrow(() -> new RuntimeException("订单不存在 " + orderSn));

        Assert.isTrue(OrdersStatusEnum.INIT.equals(orders.getStatus()), "非下单状态不能修改订单");

        List<OrdersItem> dbOrderItems = ordersItemRepository.findByOrderId(orders.getId());
        // 转map
        Map<Long, OrdersItem> ordersItemMap = dbOrderItems.stream().collect(Collectors.toMap(OrdersItem::getGoodsId, e -> e));

        List<OrdersItem> tempList = new ArrayList<>(dbOrderItems);

        for (OrderItemDto requestOrderItem : request.getOrderItemSet()) {
            final Long goodsId = requestOrderItem.getGoodsId();
            final int quantity = requestOrderItem.getQuantity();

            if (quantity == 0) {
                continue;
            }

            // 加菜
            if (requestOrderItem.isAdd()) {
                // 存在DB里面
                if (ordersItemMap.containsKey(goodsId)) {
                    OrdersItem ordersItem = ordersItemMap.get(goodsId);
                    ordersItem.setQuantity(ordersItem.getQuantity() + quantity);
                    ordersItemRepository.save(ordersItem);
                } else {
                    OrdersItem ordersItem = new OrdersItem();
                    ordersItem.setCompleteNum(0);
                    ordersItem.setQuantity(quantity);
                    ordersItem.setOrderId(orders.getId());
                    ordersItem.setGoodsId(goodsId);
                    ordersItemRepository.save(ordersItem);
                    tempList.add(ordersItem);
                }
                // 扣库存
                int effectRow = goodsRepository.reduceStock(goodsId, quantity);
                Assert.isTrue(effectRow > 0, "库存不足");
            } else {
                // 退菜
                // 存在DB里面
                if (ordersItemMap.containsKey(goodsId)) {
                    OrdersItem ordersItem = ordersItemMap.get(goodsId);
                    Integer oldQuantity = ordersItem.getQuantity();
                    int newQuantity = oldQuantity - quantity;
                    // 退菜之后的数量不能小于已上菜数量
                    Assert.isTrue(newQuantity >= ordersItem.getCompleteNum(), "退菜之后的数量不能小于已上菜数量");
                    ordersItem.setQuantity(newQuantity);
                    if (newQuantity > 0) {
                        ordersItemRepository.save(ordersItem);
                    } else {
                        tempList.remove(ordersItem);
                        ordersItemRepository.delete(ordersItem);
                    }
                    // 加库存
                    goodsRepository.addStock(goodsId, quantity);


                } else {
                    log.warn("退菜且该商品不存在订单详情中，非法请求");
                }

            }

        }

        orders.setItemList(tempList);
        // 计算价格
        calculationAmount(orders);
        // 跟新orders
        ordersRepository.save(orders);
    }

    /**
     * 功能描述: 查看订单
     * @param: [request]
     * @author: liujin
     * @date: 2020/12/18 16:50
     */
    @Override
    public List<Orders> page(OrdersPageRequest request) {
        final String orderSn = request.getOrderSn();
        PageRequest pageRequest = PageRequest.of(request.getPageNum(), request.getPageSize());
        Page<Orders> page = ordersRepository.findAll((Specification<Orders>) (root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> list = new LinkedList<>();
            if (!StringUtils.isEmpty(orderSn)) {
                list.add(criteriaBuilder.equal(root.get("sn"), orderSn));
            }
            return criteriaBuilder.and(list.toArray(new Predicate[0]));
        }, pageRequest);

        List<Orders> ordersList = page.getContent();
        ordersList.forEach(e -> {
            e.setItemList(ordersItemRepository.findByOrderId(e.getId()));
        });
        return ordersList;
    }

    /**
     * 功能描述: 确认已完成上菜的菜品数量
     * @param: [orderItemId]
     * @author: liujin
     * @date: 2020/12/18 19:20
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void confirm(OrderItemConfirmRequest request) {
        // 更新上菜数量
        Long ordersItemId = request.getOrdersItemId();
        OrdersItem ordersItem = ordersItemRepository.select4update(ordersItemId);
        // 判断确认菜品数量不能大于菜品数量
        Assert.isTrue(ordersItem.getQuantity() >= request.getQuantity(), "确认菜品数量不能大于菜品数量");
        // 设置上菜数量数量
        ordersItem.setCompleteNum(request.getQuantity());
        ordersItemRepository.save(ordersItem);
        Orders orders = ordersRepository.getOne(ordersItem.getOrderId());
        // 判断订单当前状态不能确认已完成上菜的菜品
        Assert.isTrue(orders.getStatus().equals(OrdersStatusEnum.INIT), "订单当前状态不能确认已完成上菜的菜品");
    }
}
